﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawInTexture : MonoBehaviour {
    public enum ColorBlendType {
        UseColor,
        UseTexture,

        /// <summary>
        /// Use the intermediate color between the color of the brush and the color of the texture.
        /// </summary>
        Neutral,
    }

    public ColorBlendType colorBlendType = ColorBlendType.UseTexture;
    public Texture2D texture;
    public Color color = Color.white;
    public int brushSize = 100;
    public Texture2D brush;


    void Start() {

    }

    void Update() {
        if (!Input.GetMouseButton(0))
            return;

        RaycastHit hit;

        if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit))
            return;

        var renderer = hit.transform.GetComponent<Renderer>();
        var meshCollider = hit.collider as MeshCollider;

        if (renderer == null || renderer.sharedMaterial == null || renderer.sharedMaterial.mainTexture == null || meshCollider == null)
            return;

        var tex2D = renderer.material.mainTexture as Texture2D;
        Vector2 pixelUV = hit.textureCoord;
        pixelUV.x *= tex2D.width;
        pixelUV.y *= tex2D.height;
        var x = (int)pixelUV.x - (int)(brushSize * 0.5);
        var y = (int)pixelUV.y - (int)(brushSize * 0.5);
        var w = brushSize;
        var h = brushSize;

        if (x < 0) {
            w += x;
            x = 0;
        } else if (x > (tex2D.width - w)) {
            w -= (x - (tex2D.width - w));
        }

        if (y < 0) {
            h += y;
            y = 0;
        } else if (y > (tex2D.height - h)) {
            h -= (y - (tex2D.height - h));
        }
        
        Color[] colors = new Color[w * h];
        Color[] bgColors = tex2D.GetPixels(x, y, w, h);

        switch (colorBlendType) {
            case ColorBlendType.UseTexture:
                if (texture != null) {
                    if (texture.width < tex2D.width && texture.height < tex2D.height) {
                        colors = ScaleTexture(texture, w, h).GetPixels();
                    } else {
                        colors = texture.GetPixels(x, y, w, h);
                    }
                }
                break;

            case ColorBlendType.UseColor:
                for (var i = 0; i < colors.Length; i++) {
                    colors[i] = Color.Lerp(bgColors[i], color, color.a);
                }
                break;

            case ColorBlendType.Neutral:
                if (texture != null) {
                    colors = texture.GetPixels(x, y, w, h);

                    for (var i = 0; i < colors.Length; i++) {
                        colors[i] *= color;
                    }
                }
                break;
        }

        if (brush != null) {
            var brushColors = ScaleTexture(brush, w, h).GetPixels();

            for (var i = 0; i < brushColors.Length; i++) {
                colors[i] = Color.Lerp(bgColors[i], colors[i], brushColors[i].a);
            }
        }

        tex2D.SetPixels(x, y, w, h, colors);
        tex2D.Apply();
    }

    public static Texture2D ScaleTexture(Texture2D source, int width, int height, bool enableBilinear = true) {
        var tex2D = new Texture2D(width, height, source.format, false);

        for (var i = 0; i < width; i++) {
            for (var j = 0; j < height; j++) {
                Color c;

                if (enableBilinear) {
                    c = source.GetPixelBilinear((float)i / width, (float)j / height);
                } else {
                    c = source.GetPixel(i, j);
                }

                tex2D.SetPixel(i, j, c);
            }
        }

        tex2D.Apply();
        return tex2D;
    }
}
